package com.kusen.cas;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * 处理ABA问题的：AtomicStampedReference类版本控制
 */
public class ABADome {
    //没有加版本控制的cas
    static AtomicReference<Integer> atomicReference = new AtomicReference<>(100);
    //使用版本控制
    static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100, 1);

    public static void main(String[] args) {
        /**
         * 创建两个线程来模拟ABA问题
         */
        new Thread(() -> {
            System.out.println(atomicReference.compareAndSet(100, 101) + "内存中的值为：" + atomicReference.get());
            System.out.println(atomicReference.compareAndSet(101, 100) + "内存中的值为：" + atomicReference.get());
        }, "A").start();

        new Thread(() -> {
            //这个睡眠时间保证在上面能产生ABA问题
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(atomicReference.compareAndSet(100, 1024) + "内存中的值为：" + atomicReference.get());
        }, "A").start();
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("===============以下是ABA问题的解决=======================");
        new Thread(() -> {
            //获取当前版本
            int stamp = atomicStampedReference.getStamp();
            System.out.println(Thread.currentThread().getName() + "：当前版本为：" + stamp);
            //保证这个线程能拿到第一次的版本
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //当前线程是要模拟ABA问题
            boolean state = atomicStampedReference.compareAndSet(100, 101, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);
            System.out.println(Thread.currentThread().getName() + "\t" + state + "\t单前版本：" + atomicStampedReference.getStamp() + "\t当前值为：" + atomicStampedReference.getReference());
            boolean state2 = atomicStampedReference.compareAndSet(101, 100, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);
            System.out.println(Thread.currentThread().getName() + "\t" + state2 + "\t单前版本：" + atomicStampedReference.getStamp() + "\t当前值为：" + atomicStampedReference.getReference());

        }, "C").start();
        new Thread(() -> {
            //获取当前版本
            int stamp = atomicStampedReference.getStamp();
            System.out.println(Thread.currentThread().getName() + "：当前版本为：" + stamp);
            //保证这个线程能拿到第一次的版本
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            boolean state = atomicStampedReference.compareAndSet(100, 1024, stamp, stamp + 1);
            System.out.println(Thread.currentThread().getName() + "\t" + state + "\t第2次版本：" + stamp + "\t当前值为：" + atomicStampedReference.getReference());

        }, "D").start();
    }
}
